<?php

class SM_TestCase
{
    public function __construct()
    {
    }

    public function setUp()
    { }

    public function tearDown()
    { }

    protected function assertEquals($expected, $actual)
    {
        if ($expected != $actual)
            throw new Exception('Expected <br><pre>' . htmlspecialchars($expected) . '</pre>but was <br><pre>' . htmlspecialchars($actual) . '</pre>');
    }

    protected function isTrue($expected)
    {
        if ($expected != true)
            throw new Exception('Expected true, but was false');
    }

    protected function isFalse($expected)
    {
        if ($expected != false)
            throw new Exception('Expected false, but was true');
    }
}

class TestRunner
{
    private $tests;

    public function __construct()
    {
        $this->tests = array();
    }

    public function RegisterTest($testObject)
    {
        $this->tests[] = $testObject;
    }

    public function RunTests()
    {
        echo '<table border="0" cellspacing="0">';
        
        echo '<tr>';
        echo '<td style="width: 20px">';
        echo '</td>';
        echo '<td>';
        echo '</td>';
        echo '<td style="width: 40px">';
        echo '</td>';
        echo '</tr>';

        foreach($this->tests as $test)
        {
            $this->RunTest($test);
        }
        echo '</table>';
    }

    private function RunTest($test)
    {
        $methodNames = get_class_methods( get_class($test) );

        echo '<tr>';
        echo '<td colspan="3" style="background-color: #000; height: 2px;">';
        echo '</td>';
        echo '</tr>';
        
        echo '<tr>';
        echo '<td colspan="3">';
        echo get_class($test);
        echo '</td>';
        echo '</tr>';

        foreach($methodNames as $methodName)
        {
            $success = true;
            $failMessage = '';
            
            if ((strpos($methodName, 'test') === false) || (strpos($methodName, 'test') > 0))
                continue;

            try
            {
                $test->setUp();
            }
            catch (Exception $exception)
            {
                $success = false;
                $failMessage = 'Setup failed: ' . $exception->getMessage();
            }

            try
            {
                call_user_func(array($test, $methodName));
            }
            catch (Exception $exception)
            {
                $success = false;
                $failMessage = $exception->getMessage();
            }

            try
            {
                $test->tearDown();
            }
            catch (Exception $exception)
            {
                $success = false;
                $failMessage = 'Teardown failed: ' . $exception->getMessage();
            }

            $this->WriteTestResults($methodName, $success, $failMessage);

        }
    }

    private function WriteTestResults($methodName, $success, $failMessage)
    {
        echo '<tr>';
        echo '<td colspan=2>';
        echo $methodName;
        echo '</td>';
        echo '<td style="width: 40px; background-color: ' . ($success ? 'green' : 'red') . '">';
        echo '</td>';
        echo '</tr>';

        if (!$success)
        {
            echo '<tr>';
            echo '<td style="width: 20px;">';
            echo '</td>';
            echo '<td colspan=2>';
            echo $failMessage;
            echo '</td>';
            echo '</tr>';
        }
    }
}

$testRunner = new TestRunner();

function RegisterTest($testObject)
{
    global $testRunner;
    $testRunner->RegisterTest($testObject);
}

function RunTests()
{
    global $testRunner;
    $testRunner->RunTests();
}

?>
